package com.msmall.base;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CascadeCollection<T> {
	public static final String ORDERS_ASC = "ASC";
	public static final String ORDERS_DESC = "DESC";
	
	private static final Log log = LogFactory.getLog(CascadeCollection.class);
	
	/**
	 * 当前数据
	 */
	protected T current;
	/**
	 * 父级别
	 */
	protected List<CascadeCollection<T>> parents;
	/**
	 * 父级别的第一个
	 */
	protected CascadeCollection<T> firstParent;
	
	/**
	 * 子级别
	 */
	protected List<CascadeCollection<T>> children;
	
	/**
	 * 存放所有的数据
	 */
	protected Map<Object, CascadeCollection<T>> allDatas;
	
	/**
	 * 顶层数据
	 */
	protected List<CascadeCollection<T>> topLevels;
	
	/**
	 * @param datas
	 * @param key
	 * @param parentKey
	 * @param ordersKey
	 * @param order
	 */
	public void parserLong(List<T> datas, Long topId, String key, String parentKey, String ordersKey, String order){
		try{
			if(datas == null)
				return; 
			if(!(ORDERS_ASC.equalsIgnoreCase(order) || (ORDERS_DESC.equalsIgnoreCase(order)))){
				order = ORDERS_ASC;
			}
			Long id = null;
			Long parentid = null;
			for(int i=0; i<datas.size(); i++){
				T obj = datas.get(i);
				id = getLongId(obj, key);
				parentid = getLongId(obj, parentKey);
				
				if(id == null || parentid == null){
					log.debug("========> NullPoint " + obj.getClass() + " id=" +id + "  parentid="+parentid);
					return;
				}
				CascadeCollection<T> current = new CascadeCollection<T>();
				current.setCurrent(obj);
				addAllDatas(id, current);
				if(topId.compareTo(parentid) == 0){
					 addTopLevels(current, ordersKey, order);
				}
			}
			Iterator<CascadeCollection<T>> its = allDatas.values().iterator();
			while(its.hasNext()){
				CascadeCollection<T> obj = its.next();
				T current = obj.getCurrent();
				CascadeCollection<T> parent = null;
				id = getLongId(current, key);
				parentid = getLongId(current, parentKey);
				if(topId.compareTo(parentid) != 0){
					parent = allDatas.get(parentid);
					obj.addParents(parent, ordersKey, order );
					parent.addChildren(obj, ordersKey, order);
				}
				obj.setAllDatas(allDatas);
				obj.setTopLevels(topLevels);
			}
			
		}catch(Exception e){
			log.debug(e);
		}
	}
	
	public void parserInt(List<T> datas, Integer topId, String key, String parentKey, String ordersKey, String order){
		try{
			if(datas == null)
				return; 
			if(!(ORDERS_ASC.equalsIgnoreCase(order) || (ORDERS_DESC.equalsIgnoreCase(order)))){
				order = ORDERS_ASC;
			}
			Integer id = null;
			Integer parentid = null;
			for(int i=0; i<datas.size(); i++){
				T obj = datas.get(i);
				id = getInteger(obj, key);
				parentid = getInteger(obj, parentKey);
				
				if(id == null || parentid == null){
					log.debug("========> NullPoint " + obj.getClass() + " id=" +id + "  parentid="+parentid);
					return;
				}
				CascadeCollection<T> current = new CascadeCollection<T>();
				current.setCurrent(obj);
				addAllDatas(id, current);
				if(topId.compareTo(parentid) == 0){
					 addTopLevels(current, ordersKey, order);
				}
			}
			Iterator<CascadeCollection<T>> its = allDatas.values().iterator();
			while(its.hasNext()){
				CascadeCollection<T> obj = its.next();
				T current = obj.getCurrent();
				CascadeCollection<T> parent = null;
				id = getInteger(current, key);
				parentid = getInteger(current, parentKey);
				if(topId.compareTo(parentid) != 0){
					parent = allDatas.get(parentid);
					obj.addParents(parent, ordersKey, order );
					parent.addChildren(obj, ordersKey, order);
				}
				obj.setAllDatas(allDatas);
				obj.setTopLevels(topLevels);
			}
			
		}catch(Exception e){
			log.debug(e);
		}
	}
	public int getInteger(Object obj, String key){
		try {
			String s = BeanUtils.getProperty(obj, key);
			if(StringUtils.isEmpty(s))
				return 0;
			return Integer.parseInt(s);
		} catch (Exception e) {
			log.debug(e);
		}
		return 0;
	}
	public Long getLongId(Object obj, String key){
		try {
			return Long.parseLong(BeanUtils.getProperty(obj, key));
		} catch (Exception e) {
			log.debug(e);
		}
		return null;
	}

	public void addTopLevels(CascadeCollection<T> obj, String ordersKey, String order){
		if(topLevels == null)
			topLevels = new ArrayList<CascadeCollection<T>>();
		addInOrders(topLevels, obj, ordersKey, order);
	}
	
	private void addInOrders(List<CascadeCollection<T>> list, CascadeCollection<T> obj, String ordersKey, String order){
		if(list.size() == 0){
			list.add(obj);
			return ;
		}
		int orders = getInteger(obj.getCurrent(), ordersKey);
		int i = list.size()-1;
		for(; i>=0;i--){
			T temp = list.get(i).getCurrent();
			int tempInt = getInteger(temp, ordersKey);
			if(ORDERS_ASC.equals(order)){
				if(orders > tempInt){
					break;
				}
			}else{
				if(orders < tempInt){
					break;
				}
			}
		}
		list.add(i+1, obj);
	}
	public void addAllDatas(Object key, CascadeCollection<T> obj){
		if(allDatas == null)
			allDatas = new HashMap<Object, CascadeCollection<T>>();
		allDatas.put(key, obj);
	}
	public void addParents(CascadeCollection<T> obj, String ordersKey, String order){
		if(parents == null)
			parents = new ArrayList<CascadeCollection<T>>();
		addInOrders(parents, obj, ordersKey, order);
	}
	public void addChildren(CascadeCollection<T> obj, String ordersKey, String order){
		if(children == null)
			children = new ArrayList<CascadeCollection<T>>();
		addInOrders(children, obj, ordersKey, order);
	}
	
	public T getCurrent() {
		return current;
	}

	public void setCurrent(T current) {
		this.current = current;
	}

	public List<CascadeCollection<T>> getParents() {
		return parents;
	}

	public void setParents(List<CascadeCollection<T>> parents) {
		this.parents = parents;
	}

	public List<CascadeCollection<T>> getChildren() {
		return children;
	}

	public void setChildren(List<CascadeCollection<T>> children) {
		this.children = children;
	}

	public Map<Object, CascadeCollection<T>> getAllDatas() {
		return allDatas;
	}


	public void setAllDatas(Map<Object, CascadeCollection<T>> allDatas) {
		this.allDatas = allDatas;
	}


	public List<CascadeCollection<T>> getTopLevels() {
		return topLevels;
	}

	public void setTopLevels(List<CascadeCollection<T>> topLevels) {
		this.topLevels = topLevels;
	}
	
	public CascadeCollection<T> getFirstParent() {
		return parents.get(0);
	}
	public void setFirstParent(CascadeCollection<T> firstParent) {
		this.firstParent = firstParent;
	}
}
